home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / OS Utilities / SnapshotSample1.0b4 / SnapshotSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-29  |  11.2 KB  |  409 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        SnapshotSample.c
  3.  
  4.     Contains:    Code for saving and restoring desktop icons.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. /*
  22.     This sample, when run the first time, creates a 
  23.     snapshot file in the Preferences folder which contains a list 
  24.     of the names and locations fo the items on the 
  25.     desktop.
  26.     
  27.     Running the sample again will read the snapshot
  28.     file and tell the Finder to position the items
  29.     at the locations read from the snapshot file.
  30.     
  31.     Sample does not read/set location of Trash,
  32.     nor of mounted volumes.
  33.     
  34.     Sample is provided as is... I didn't get much 
  35.     chance to test beyond the standard, "oh, this
  36.     works!" stage.
  37.     
  38.     The original Pascal version was written by
  39.     Quinn "The Eskimo!" and released as a Freeware
  40.     utility.  This DTS sample was created by
  41.     Deborah Grits.  This version was tidied up
  42.     and released by Quinn "The Eskimo!".
  43.     
  44.     Oh what a tangled web we weave...
  45. */
  46.     
  47. #include <AppleEvents.h>
  48. #include <Errors.h>
  49. #include <Events.h>
  50. #include <Fonts.h>
  51. #include <Gestalt.h>
  52. #include <Memory.h>
  53. #include <Menus.h>
  54. #include <OSUtils.h>
  55. #include <QDOffscreen.h>
  56. #include <QuickDraw.h>
  57. #include <Resources.h>
  58. #include <Script.h>
  59. #include <ToolUtils.h>
  60. #include <Windows.h>
  61.  
  62. //////////////////////////////////////////////////////////////////////////
  63. // Basic Utilities
  64.  
  65. static OSErr FindProcessByTypeAndCreator(OSType typeToFind, OSType creatorToFind, ProcessSerialNumber *processSN)
  66.     // Runs through the process list looking for the indicated application.
  67. {
  68.     OSErr err;
  69.         ProcessInfoRec infoRecToFill;
  70.         
  71.     err = noErr;
  72.     processSN->lowLongOfPSN = kNoProcess;
  73.     processSN->highLongOfPSN = kNoProcess;
  74.     infoRecToFill.processInfoLength = sizeof(ProcessInfoRec);
  75.     infoRecToFill.processName = nil;
  76.     infoRecToFill.processAppSpec = nil;
  77.     do {
  78.         err = GetNextProcess(processSN);
  79.         if (err == noErr) {
  80.             GetProcessInformation(processSN, &infoRecToFill);
  81.         }
  82.     } while ((infoRecToFill.processSignature != creatorToFind || infoRecToFill.processType != typeToFind) ||
  83.                    err != noErr);
  84.     
  85.     return(err);
  86. }
  87.  
  88. //////////////////////////////////////////////////////////////////////////
  89. // Global Types
  90.  
  91. // The snapshot file is made up of records of SnapRecord type.
  92. // An empty record (ie with name == "") is used to indicate
  93. // the end of the file.
  94.  
  95. typedef struct 
  96. {
  97.     Str63 name;
  98.     Point loc;
  99. } SnapRecord, *SnapRecordPtr, **SnapRecordHandle;
  100.  
  101.  
  102. //////////////////////////////////////////////////////////////////////////
  103. // Global Variables
  104.  
  105. // Used to tell the main event loop to quit.
  106.  
  107. static Boolean gQuit = false;
  108.  
  109. // An empty AppleEvent Descriptor.
  110.  
  111. const static AEDesc gNullDesc = {typeNull, nil};
  112.  
  113. //////////////////////////////////////////////////////////////////////////
  114. // Restoring Snapshots
  115.  
  116. static OSErr SetItemPosition(Str255 fname, Point dest, AEDesc *setDataEvent)
  117.     // Sends an AppleEvent to the targetDesc (which should target the Finder)
  118.     //  to set the position of the item whose name is fname to the position dest.
  119. {
  120.     OSErr        err;
  121.     AEDesc        fileNameDesc         = gNullDesc;
  122.     AEDesc        rootDesc             = gNullDesc;
  123.     AEDesc        propertyDescriptor     = gNullDesc;
  124.     AEDesc        objParentDesc         = gNullDesc;
  125.     AEDesc        objDesc             = gNullDesc;
  126.     AEDesc        reply                 = gNullDesc;
  127.     AEDesc        newData             = gNullDesc;
  128.     DescType    procDescData         = 'posn';
  129.  
  130.     err = AECreateDesc(typeChar, &fname[1], fname[0], &fileNameDesc);
  131.         
  132.     // Create objParentDesc to specify the parent object, ie item "xxxx" of application
  133.     if (err == noErr) {
  134.         err = CreateObjSpecifier(cObject, &rootDesc, formName, &fileNameDesc, false, &objParentDesc);
  135.     }
  136.  
  137.     // Create propertyDescriptor to hold the property specifier, ie position
  138.     if (err == noErr) {
  139.         err = AECreateDesc(typeType, &procDescData, sizeof(procDescData), &propertyDescriptor);
  140.     }
  141.     
  142.     // Create objDesc to reference the data to set, ie position of item "xxx" of application
  143.     if (err == noErr) {
  144.         err = CreateObjSpecifier(cProperty, &objParentDesc, formPropertyID, &propertyDescriptor, false, &objDesc);
  145.     }
  146.  
  147.     // Create on descriptor to hold the new data, ie the new icon position.
  148.     if (err == noErr) {
  149.         err = AECreateDesc(typeQDPoint, (void*)&dest, sizeof(dest), &newData);
  150.     }
  151.  
  152.     // Fill out the parameters, putting the objDesc into the direct object and the new data
  153.     //  into the data parameter.
  154.     if (err == noErr) {
  155.         err = AEPutParamDesc(setDataEvent, keyDirectObject, &objDesc);
  156.     }
  157.     if (err == noErr) {
  158.         err = AEPutParamDesc(setDataEvent, keyAEData, &newData);
  159.     }
  160.  
  161.     // Send the event.
  162.     if (err == noErr) {
  163.         err = AESend(setDataEvent, &reply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
  164.         
  165.         // Some code that I enable when I'm debugging.
  166.         
  167.         if (false) {
  168.             long errNum;
  169.             Str255      errStr;
  170.             DescType    junkType;
  171.             Size        realSize;
  172.             
  173.             err = AEGetParamPtr(&reply, keyErrorNumber, typeInteger, &junkType, &errNum, sizeof(errNum), &realSize);
  174.             err = AEGetParamPtr(&reply, keyErrorString, typeChar, &junkType, &errStr[1], 255, &realSize);
  175.             errStr[0] = realSize;
  176.         }
  177.     }
  178.  
  179.     // Clean up all those messy descriptors.  Don't you just love AppleEvents (-:
  180.     AEDisposeDesc(&rootDesc);
  181.     AEDisposeDesc(&fileNameDesc);
  182.     AEDisposeDesc(&objParentDesc);
  183.     AEDisposeDesc(&propertyDescriptor);
  184.     AEDisposeDesc(&objDesc);
  185.     AEDisposeDesc(&newData);
  186.     AEDisposeDesc(&reply);
  187.     
  188.     return err;
  189. }
  190.  
  191. static OSErr RestoreSnapshot (FSSpec snapFss)
  192.     // Restore the snapshot file specified by snapFss.
  193. {
  194.     OSErr                err;
  195.     ProcessSerialNumber finderPSN;
  196.     AEDesc                targetDesc         = gNullDesc;
  197.     AEDesc                setDataEvent     = gNullDesc;
  198.     short                snapFileRef;
  199.     Boolean             done;
  200.     SnapRecord            aSnapRecord;
  201.     long                byteCount;
  202.  
  203.     snapFileRef = 0;
  204.     
  205.     // Find the Finder's ProcessSerialNumber and create the targetDesc for it.
  206.     err = FindProcessByTypeAndCreator('FNDR', 'MACS', &finderPSN);
  207.     if (err == noErr) {
  208.         err = AECreateDesc(typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(finderPSN), &targetDesc);
  209.     }
  210.     // Create the AppleEvent.
  211.     if (err == noErr) {
  212.             err = AECreateAppleEvent(kAECoreSuite, kAESetData, &targetDesc,
  213.                                                                 kAutoGenerateReturnID, kAnyTransactionID, &setDataEvent);
  214.     }    
  215.     
  216.     // Open the file.
  217.     if (err == noErr) {
  218.         err = FSpOpenDF(&snapFss, fsRdPerm, &snapFileRef);
  219.     }
  220.     if (err == noErr) {
  221.         
  222.         // Read the records in the file, repositioning the icons as we go.
  223.         done = false;
  224.         do {
  225.             byteCount = sizeof(SnapRecord);
  226.             err = FSRead(snapFileRef, &byteCount, (void*) &aSnapRecord);
  227.             
  228.             if (err == noErr) {
  229.                 // We're done if we hit the empty string.
  230.                 done = (aSnapRecord.name[0] == 0);
  231.                 
  232.                 if (!done) {
  233.                     // Reposition the icon.
  234.                     err = SetItemPosition(aSnapRecord.name, aSnapRecord.loc, &setDataEvent);
  235.                 }
  236.             }
  237.         } while (!done);
  238.     }
  239.     
  240.     if (err == eofErr) {
  241.         err = noErr;
  242.     }
  243.  
  244.     // clean up
  245.     if (snapFileRef != 0) {
  246.         (void) FSClose(snapFileRef);
  247.     }
  248.     AEDisposeDesc(&setDataEvent);
  249.     AEDisposeDesc(&targetDesc);
  250.         
  251.     return err;
  252. }
  253.  
  254. //////////////////////////////////////////////////////////////////////////
  255. // Creating Snapshots
  256.  
  257. static OSErr WriteFileRecord(short snapFileRef, Str63 itemName, Point itemPosition)
  258.     // Add a new record to the snapshot file.
  259. {
  260.     OSErr        err;
  261.     SnapRecord    aSnapRecord;
  262.     long        byteCount;
  263.     
  264.     BlockMoveData(itemName, aSnapRecord.name, sizeof(aSnapRecord.name));
  265.     aSnapRecord.loc = itemPosition;
  266.     
  267.     byteCount = sizeof(SnapRecord);
  268.     err = FSWrite(snapFileRef, &byteCount, (void*) &aSnapRecord);
  269.     
  270.     return err;
  271. }
  272.  
  273. static OSErr CreateSnapshotFile(FSSpec snapFss)
  274.     // Add the positions for the icons on the desktop to the snapshot file snapFss.
  275. {
  276.     OSErr         err;
  277.     short        snapFileRef;
  278.     short        deskVRefNum;
  279.     long        deskDirID;
  280.     CInfoPBRec    pb;
  281.     short        fileIndex;
  282.     Point        folderOrigin;
  283.     Point        itemPosition;
  284.     Str63        itemName;
  285.     UInt32        systemVersion;
  286.  
  287.     snapFileRef = 0;
  288.     
  289.     // Find the desktop folder.
  290.     err = FindFolder(kOnSystemDisk, kDesktopFolderType, true, &deskVRefNum, &deskDirID);
  291.     
  292.     // Get the origin for the desktop folder.
  293.     pb.dirInfo.ioNamePtr = nil;
  294.     pb.dirInfo.ioDrDirID = deskDirID;
  295.     pb.dirInfo.ioVRefNum = deskVRefNum;
  296.     pb.dirInfo.ioFDirIndex = -1;        // get information about ioDirID
  297.     err = PBGetCatInfoSync(&pb);
  298.     if (err == noErr) {
  299.         folderOrigin.h = 0;
  300.         folderOrigin.v = 0;
  301.         if (Gestalt(gestaltSystemVersion, (long *) &systemVersion) != noErr || systemVersion < 0x0800) {
  302.             // Evil fudge factor is needed for Finder 7.x.  Finder 8.0 does not fudge.
  303.             folderOrigin.v = folderOrigin.v - 20;
  304.         }
  305.     }
  306.  
  307.     // Open up the snapshot file.
  308.     if (err == noErr) {
  309.         err = FSpOpenDF(&snapFss, fsRdWrPerm, &snapFileRef);
  310.     }
  311.  
  312.     // Loop through each file in the folder, adding it to the snapshot file.
  313.     if (err == noErr) {
  314.         fileIndex = 1;
  315.         do {
  316.                 pb.dirInfo.ioNamePtr = (StringPtr) itemName;
  317.                 pb.dirInfo.ioDrDirID = deskDirID;
  318.                 pb.dirInfo.ioVRefNum = deskVRefNum;
  319.                 pb.dirInfo.ioFDirIndex = fileIndex;
  320.                 err = PBGetCatInfoSync(&pb);
  321.                 if (err == noErr) {
  322.                     itemPosition = pb.hFileInfo.ioFlFndrInfo.fdLocation;
  323.                     SubPt(folderOrigin, &itemPosition);
  324.                     err = WriteFileRecord(snapFileRef, itemName, itemPosition);
  325.                 }
  326.                 fileIndex += 1;
  327.         } while (err == noErr);
  328.         
  329.         // Write the sentinel to the end of the file.
  330.         if (err == fnfErr) {
  331.             itemName[0] = 0;
  332.             itemPosition.h = 0;
  333.             itemPosition.v = 0;
  334.             err = WriteFileRecord(snapFileRef, itemName, itemPosition);
  335.         }
  336.     }
  337.         
  338.     // Clean up.
  339.     if (snapFileRef != 0) {
  340.         (void) FSClose(snapFileRef);
  341.     }
  342.         
  343.     return err;
  344. }
  345.  
  346. //////////////////////////////////////////////////////////////////////////
  347. // Main Line
  348.  
  349. static void InitToolbox()
  350.     // Standard Macintosh toolbox init.
  351. {
  352.     InitGraf(&qd.thePort);
  353.     InitFonts();
  354.     InitWindows();
  355.     InitMenus();
  356.     TEInit();
  357.     InitDialogs(nil);
  358.     MaxApplZone();
  359.     
  360.     MoreMasters();
  361.     MoreMasters();
  362.     MoreMasters();
  363.  
  364.     InitCursor();
  365.     FlushEvents(0, everyEvent);    
  366. }
  367.  
  368. void main(void)
  369.     // The application's main entry point.
  370. {
  371.     OSErr     err;
  372.     FSSpec    snapFss;
  373.     long    gestaltResponse;
  374.  
  375.     // First, a quick check to make sure we have Scriptable Finder.  If we don't
  376.     //  we bail quickly.
  377.     
  378.     if ((Gestalt(gestaltFinderAttr, &gestaltResponse) != noErr) || ((gestaltResponse & (1 << gestaltOSLCompliantFinder)) == 0)) {
  379.         DebugStr("\pWhoops, no Scriptable Finder.");
  380.         ExitToShell();
  381.     }
  382.  
  383.     // Now bring up the standard Mac toolbox.
  384.     InitToolbox();
  385.     
  386.     // Find the Preferences folder.
  387.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, false, &(snapFss.vRefNum), &(snapFss.parID));
  388.  
  389.     if (err == noErr) {
  390.  
  391.         // Open the snapshot file in the Preferences folder.
  392.         //  Should get this from a resource, of course.
  393.         
  394.         (void) FSMakeFSSpec(snapFss.vRefNum, snapFss.parID, "\pDesktop Snap", &snapFss);
  395.         err = FSpCreate(&snapFss, 'FRøG', 'FRøG', 0);
  396.         
  397.         if (err == dupFNErr) {                            // If we already have a snapshot file,
  398.             err = RestoreSnapshot(snapFss);                //  restore icon positions,
  399.         } else if (err == noErr) {                        // otherwise make a snapshot file.
  400.             // Create the snapshot file for the desktop
  401.             err = CreateSnapshotFile(snapFss);
  402.         }
  403.     }
  404.     
  405.     if (err != noErr) {
  406.         DebugStr("\pSnapshotter failed.");
  407.     }
  408. }
  409.